﻿!function ($) {
	$.widget('codecontrib.expressionBuilder', {
		_create: function () {
			var $plugin = this;

			if (!$plugin.element.is(':text')) {
				return;
			}

			var $itemsContainer = $('<ul/>');
			$itemsContainer.addClass('expression-builder-items-container');

			var $container = $('<div/>');
			$container.addClass('expression-builder-container')
                .addClass('ui-state-active')
                .addClass('ui-corner-all')
				.append($itemsContainer)
				.click(function (event) {
					var $currentInput = $itemsContainer.find('.expression-builder-input');

					if ($currentInput.length > 0) {
						$currentInput.focus();

						return false;
					}

					var $inputContainer = $('<li/>');

					var $input = $('<input type="text"/>');
					$plugin._trigger('initInput', null, { input: $input });
					$input.addClass('expression-builder-input')
						.blur(function () {
							var value = $input.val();

							if (value.length > 0) {
								if ($plugin.createItem(value)) {
									$input.val('');
								}
							}

							$inputContainer.remove();
						})
						.click(function (event) {
							event.stopPropagation();
						})
						.keydown(function (event) {
							var keyCode = event.which;

							if (keyCode === $.ui.keyCode.BACKSPACE) {
								if (!$input.val().trim().length) {
									$plugin.removeItem($inputContainer.prev());
								}
							}
							else if (keyCode === $.ui.keyCode.ENTER) {
								var value = $input.val().trim();

								if (value.length > 0) {
									if ($plugin.createItem(value)) {
										$input.val('');
									}

									return false;
								}
							}
							else if (keyCode === $.ui.keyCode.LEFT) {
								var $previous = $inputContainer.prev();

								if ($previous.length && !$input.val().trim().length) {
									$input.data('blur', false);

									$previous.insertAfter($inputContainer);

									$input.focus();
								}
							}
							else if (keyCode === $.ui.keyCode.RIGHT) {
								var $next = $inputContainer.next();

								if ($next.length === 1 && $input.val().trim().length === 0) {
									$input.data('blur', false);

									$next.insertBefore($inputContainer);

									$input.focus();
								}
							}
						})
						.resizable();

					$inputContainer.addClass('expression-builder-input-container')
						.append($input);

					var mouseX = event.pageX;
					var mouseY = event.pageY;

					var wasInserted = false;

					$itemsContainer.children().each(function (i) {
						var $item = $(this);
						var itemOffset = $item.offset();
						var itemLeft = itemOffset.left;
						var itemTop = itemOffset.top;
						var itemBottom = itemTop + $item.height();

						if (mouseX < itemLeft && (mouseY >= itemTop && mouseY <= itemBottom)) {
							$inputContainer.insertBefore($item);

							wasInserted = true;

							return false;
						}
					});

					if (!wasInserted) {
						$itemsContainer.append($inputContainer);
					}

					$input.focus();
				});

			$container.insertBefore($plugin.element);

			$plugin.createItem($plugin.element.val());

			if ($plugin.options.items) {
				$.each($plugin.options.items, function (i, item) {
					$plugin.createItem(item);
				});
			}

			$plugin.element.hide();
		},
		createItem: function (text, value) {
			var $plugin = this;

			if (!text || !text.length) {
				return;
			}

			if (value && value.length) {
				if (!$plugin._trigger('validate', null, { value: value })) {
					return false;
				}

				this._createItem(text, value);
			}
			else {
				var tokens = $plugin._parseFormula(text);

				for (var i = 0; i < tokens.length; i++) {
					var token = tokens[i];

					if (!$plugin._trigger('validate', null, { value: token })) {
						continue;
					}

					this._createItem(token, token);
				};
			}

			$plugin._updateElement();

			return true;
		},
		_createItem: function (text, value) {
			var $plugin = this;

			var $itemsContainer = $plugin._itemsContainer();

			var $item = $('<li/>');
			$item.addClass('expression-builder-item')
                .addClass('ui-corner-all')
                .addClass('ui-state-default')
                .addClass('ui-widget')
				.append($plugin._itemTemplate(text))
				.click(function () {
					return false;
				})
				.data('value', value);

			var $inputContainer = $itemsContainer.children('.expression-builder-input-container');

			if (!$inputContainer.length) {
				$itemsContainer.append($item);
			}
			else {
				$item.insertBefore($inputContainer);
			}

			this._setupItemEvents($item);
		},
		destroy: function () {
			var $plugin = this;

			$plugin._container.remove();
			$plugin.element.show();

			$.Widget.prototype.destroy.call($plugin);

		},
		_container: function () {
			var $plugin = this;

			return $plugin.element.prev();
		},
		_items: function () {
			var $plugin = this;

			return $plugin._itemsContainer().children('li');
		},
		_itemsContainer: function () {
			var $plugin = this;

			return $plugin._container().children('ul:first');
		},
		_itemTemplate: function (text) {
			var $plugin = this;

			// TODO Create a callback method for displaying the text.

			return $('<span/>').append(text);
		},
		options: {
			items: [],
			initInput: function ($input) {
			},
			validate: function (event, ui) {
				return (ui.value && ui.value.length > 0);
			}
		},
		_parseFormula: function (formula) {
			var $plugin = this;

			var tokens = new Array();
			var tokenStartIndex = 0;

			for (var segmentIndex = 0; segmentIndex < formula.length; segmentIndex++) {
				var currentChar = formula.charAt(segmentIndex);

				if (currentChar
					&& currentChar.match(/[\+\-\/\*\=\(\)]/)) {
					if (tokenStartIndex < segmentIndex) {
						// Add the previous segment.
						tokens[tokens.length] = formula.substring(tokenStartIndex, segmentIndex).trim();
					}

					tokens[tokens.length] = currentChar;

					tokenStartIndex = segmentIndex + 1;
				}
			}

			if (tokenStartIndex < formula.length) {
				// There is only one item or add the last one.
				tokens[tokens.length] = formula.substring(tokenStartIndex, formula.length).replace(/[\[\]]/g, '').trim();
			}

			return tokens;
		},
		purgeItems: function () {
			var $plugin = this;

			$plugin._items().remove();

			$plugin._updateElement();
		},
		removeItem: function (item) {
			var $plugin = this;

			item.fadeOut(function () {
				item.remove();

				$plugin._updateElement();
			});
		},
		_setOption: function (keyCode, value) {
			var $plugin = this;

			$plugin.options[keyCode] = value;
		},
		_setupItemEvents: function ($item) {
			var $plugin = this;

			if (!$item.children('.expression-builder-item-delete')) {
				var $deleteLinkText = $('<span/>');
				$deleteLinkText.addClass('ui-icon')
					.addClass('ui-icon-close');

				var $deleteLinkContainer = $('<a/>');
				$deleteLinkContainer.addClass('expression-builder-item-delete')
					.append($deleteLinkText)
					.click(function () {
						$plugin.removeItem($item);
					});

				$item.append($deleteLinkContainer);
			}
		},
		_updateElement: function () {
			var $plugin = this;

			var value = '';

			this._itemsContainer().children('.expression-builder-item').each(function () {

				var itemValue = $(this).data('value');

				if (!itemValue) {
					return;
				}

				value += itemValue;
			});

			this.element.val(value);
		}
	});
} (window.jQuery)